package com.stars.easyms.feign.autoconfigure;

import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.netflix.config.ConfigurationManager;
import com.stars.easyms.base.util.FastJsonUtil;
import com.stars.easyms.feign.request.EasyMsFeignRequestInterceptor;
import com.stars.easyms.feign.response.EasyMsFeignDecoder;
import com.stars.easyms.feign.response.EasyMsFeignOptionalDecoder;
import com.stars.easyms.feign.request.EasyMsFeignEncoder;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.util.Collections;

/**
 * Feign自动配置类，为feign增加request拦截配置
 *
 * @author guoguifang
 * @date 2020-08-15 10:12
 * @since 1.6.1
 */
@Configuration
public class EasyMsFeignAutoConfiguration {

    private FastJsonHttpMessageConverter fastJsonHttpMessageConverter;

    private ObjectFactory<HttpMessageConverters> messageConverters;

    public EasyMsFeignAutoConfiguration(ObjectFactory<HttpMessageConverters> messageConverters) {
        this.fastJsonHttpMessageConverter = FastJsonUtil.getFastJsonHttpMessageConverter();
        this.messageConverters = messageConverters;
        ConfigurationManager.getConfigInstance().setProperty("ribbon.ConnectTimeout", 3000L);
        ConfigurationManager.getConfigInstance().setProperty("ribbon.ReadTimeout", 5000L);
    }

    @Bean
    public RequestInterceptor easyMsFeignRequestInterceptor() {
        return new EasyMsFeignRequestInterceptor();
    }

    @Bean
    @Primary
    public Encoder easyMsFeignEncoder() {
        return new EasyMsFeignEncoder(new SpringEncoder(feignHttpMessageConverter()));
    }

    @Bean
    @Primary
    public Decoder easyMsFeignDecoder() {
        return new EasyMsFeignOptionalDecoder(new EasyMsFeignDecoder(
                new SpringDecoder(feignHttpMessageConverter()), new SpringDecoder(this.messageConverters)));
    }

    @Bean
    public RestTemplate easyMsRestTemplate() {
        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory());
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
        restTemplate.setMessageConverters(Collections.singletonList(fastJsonHttpMessageConverter));
        return restTemplate;
    }

    private static ClientHttpRequestFactory clientHttpRequestFactory() {
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
        // 整个连接池的并发
        poolingHttpClientConnectionManager.setMaxTotal(1000);
        // 每个主机的并发
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(1000);
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
        // 重启策略
        httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true));
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build());
        // 设置超时时间，毫秒
        clientHttpRequestFactory.setConnectTimeout(5000);
        clientHttpRequestFactory.setReadTimeout(5000);
        clientHttpRequestFactory.setConnectionRequestTimeout(5000);
        return clientHttpRequestFactory;
    }

    private ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() {
        return () -> new HttpMessageConverters(fastJsonHttpMessageConverter);
    }
}
